import os
import uuid
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import START, MessagesState, StateGraph
from langchain_openai import ChatOpenAI
# from langchain.prompts import PromptTemplate
from langchain_core.messages import HumanMessage, AIMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

from data_interface.getEventsFromLocal import getEventsInfo, getEventsPrice, getEventsTikes

# 配置环境变量
os.environ["OPENAI_API_KEY"] = ""
os.environ["OPENAI_API_BASE"] = "https://api.gptsapi.net/v1"
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGSMITH_TRACING"] = "true"
os.environ["LANGSMITH_API_KEY"] = "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"
os.environ["LANGSMITH_ENDPOINT"] = "https://api.smith.langchain.com"
os.environ["LANGCHAIN_PROJECT"] = "pr-silver-spool-85"

# 获取赛事信息，为了方便从本地CSV文件中读取预先准备的赛事信息
infor=str(getEventsInfo())
price = str(getEventsPrice())
tickes = str(getEventsTikes())


# 初始化模型
model = ChatOpenAI(model="gpt-4o-mini")

# 自定义的 Prompt
prompt_template = ChatPromptTemplate.from_messages(
    [
        (
            "system",
        "1. Your role: You are a professional who sells tickets for various sports events. Your name is SpotsHub. You need to introduce yourself and ask the customer to introduce your name. You need to tell the customer the services you can provide, including providing event information, ticket prices, and ticket purchases.\n\n\
        2. The information you have comes from three tables: event information and event ticket price information. Event information comes from the event information table: [eventsInfo]:{eventsInfo}. Ticket price information comes from the event price table: [eventsPrice]:{eventsPrice}. The remaining tickets for the event come from the remaining ticket table: [remainingTickets]:{remainingTickets}. The EventID items in the three tables are unique and identical, and can be used to associate the three tables.\n\n\
        3. What you need to do:\n\
            3.1 Please output all the information that needs to be displayed to the customer in a table format. When the customer needs to select a specific event based on your prompt information, please ask the customer to enter the event ID, which is the EventID in the table.\n\
            3.2 You need to find the events that the customer is interested in from the event information table through the dialogue, and then merge the rows with the same EventID in the event information table and the event price table and display them to the customer. \n\
            3.3 You need to ask the customer to confirm the EventID number, seat level and quantity of the event he is interested in. \n\
            3.4 You need to ask the customer to confirm his ticket information, quantity, unit price and total price. \n\
            3.5 **Data verification**: After the customer confirms the ticket level and quantity, be sure to carefully check whether the quantity in the remaining ticket table meets the customer's needs. Because the remaining tickets may change dynamically, never use the data in the cache. If it does not meet the requirements, you need to prompt the customer to reconsider the ticket level or quantity purchased and re-count. If the event ticket level and quantity determined by the customer can meet the requirements, don't forget to modify the remaining tickets in the event remaining ticket table you have at the end of the transaction. \n\
            3.6 You need to ask the user to confirm the user's name and other key information that can be used to purchase tickets. \n\
            3.7 You need to ask the user to enter his valid email address. A valid email address means that the email address should contain the @ character and a part that looks like a domain name, and tell the customer that you will send the ticket information to the customer's email address."
        ),
        MessagesPlaceholder(variable_name="messages"),
    ]
    )

# 定义一个新的图
workflow = StateGraph(state_schema=MessagesState)

# 定义调用模型的函数
def call_model(state: MessagesState):
    # higlight-start
    prompt = prompt_template.invoke({
        "messages": state['messages'],# 提取实际的消息列表
        "eventsInfo": infor,  # 显式传递模板变量
        "eventsPrice": price,  # 显式传递模板变量
        "remainingTickets": tickes  # 显式传递模板变量
    })
    # higlight-end
    response = model.invoke(prompt)
    return {"messages":response}

# 定义图中的节点
workflow.add_edge(START, "model")
workflow.add_node("model", call_model)

# 添加内存
memory = MemorySaver()
app = workflow.compile(checkpointer=memory)

# 设置会话id
config = {"configurable": {"thread_id": str(uuid.uuid4())}}


# 主程序
if __name__ == "__main__":
    
    while True:
        # 获取用户输入
        user_input = input("请输入你的信息（输入 'q' 退出）：")
        if user_input.lower() == 'q':
            break
       
        try:
            input_messages = [HumanMessage(user_input)]
            
            # # 完整的信息返回
            # result=app.invoke({"messages":input_messages},config)
            # result["messages"][-1].pretty_print()
            
            # 自定义消息输出格式
            result = app.invoke({"messages": input_messages}, config)
            if result["messages"]:
                last_message = result["messages"][-1]
                if isinstance(last_message, AIMessage):
                    # 使用自定义标题替换默认的 "Ai Message"
                    print( "SpotsHub-->[" + last_message.content + "]\n")
  
                         
            # # 字符流的方式返回
            # for chunk, metadata in app.stream({"messages":input_messages},config,stream_mode="messages"):
            #     if isinstance(chunk, AIMessage):
            #         print(chunk)
            
        except Exception as e:
            print(f"发生错误: {e}")
